package testview.zhen.com.myapplication.design.consumer_producer;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 使用ReentranLock && Condition 进行处理。
 * ReentranLock使用锁，Condition根据情况将线程挂起
 * 这里存在一个问题 只使用了一个Condition 导致一时间只能有一个线程进行使用队列
 */
public class LockConditionModel implements Model  {

    private final Lock BUFFER_LOCK = new ReentrantLock();
    private final Condition BUFFER_COND = BUFFER_LOCK.newCondition();
    private final Queue<Task> buffer = new LinkedList<>();
    private final int mCap;

    private final AtomicInteger increTaskNo = new AtomicInteger(0);

    public LockConditionModel(int cap){
        this.mCap = cap;
    }

    @Override
    public Runnable newRunnableConsumer() {
        return new ConsumerImpl();
    }

    @Override
    public Runnable newRunnableProducer() {
        return new ProducerImpl();
    }

    private class ConsumerImpl extends AbstractConsumer implements Consumer,Runnable{

        @Override
        public void consume() throws InterruptedException {
            BUFFER_LOCK.lockInterruptibly();
            try {
                while (buffer.size() == 0){
                    BUFFER_COND.await();
                }
                Task task = buffer.poll();
                assert task!=null;
                //固定时间范围的消耗，模拟相对稳定的服务器处理过程
                Thread.sleep(500+(long)(Math.random()*500));
                System.out.println("consume:"+task.no);
                BUFFER_COND.signalAll();
            }finally {
                BUFFER_LOCK.unlock();
            }
        }
    }

    private class ProducerImpl extends AbstractProducer implements Producer,Runnable{

        @Override
        public void proudce() throws InterruptedException {
        //不定时生产，模拟随机的用户请求
            Thread.sleep((long)(Math.random()*1000));
            BUFFER_LOCK.lockInterruptibly();
            try {
                while (buffer.size() == mCap) {
                    System.out.println("produce---BUFFER_COND.await");
                    BUFFER_COND.await();
                }
                Task task = new Task(increTaskNo.getAndIncrement());
                buffer.offer(task);
                System.out.println("produce:"+task.no);
                System.out.println("produce---BUFFER_COND.signalAll");
                BUFFER_COND.signalAll();
            }finally {
                BUFFER_LOCK.unlock();
            }
        }
    }



}
